using System.IO.Enumeration;
using System;
using System.Reflection;
using UnityEngine;
public static class PlayerMuzzle
{
    public class Muzzle
    {
        public Vector2 firePosition = Vector2.zero;
        public Vector2 targetPosition = Vector2.right;
        public bool targetLimit = false;
        public Vector2 Direction
        {
            get
            {
                return (targetPosition - firePosition).normalized;
            }
        }

        public float Angle
        {
            get
            {
                return Vector2.SignedAngle(Vector2.right, Direction);
            }
        }

        public override string ToString()
        {
            return string.Format("Position:{0:G},TargetPosition:{1:G},Direction:{2:G},Limit:{3:G}", firePosition, targetPosition, Direction,targetLimit);
        }
    }
    public static bool GetMuzzles(PlayerContext context,out Muzzle muzzle,out Muzzle[] muzzles)
    {
        muzzle=default;
        muzzles=default;

        string stateName=context.GetPlayerState().ToString();
        string methodName=string.Format("{0:G}Normal",stateName);
        if(context.Is3DBossLevel()){
            methodName=string.Format("{0:G}3DBoss",stateName);
        }else if(context.Is3DLevel()){
            methodName=string.Format("{0:G}3D",stateName);
        }
        Type thisType= typeof(PlayerMuzzle);
        MethodInfo method=thisType.GetMethod(methodName,BindingFlags.Static|BindingFlags.NonPublic,null,new Type[]{typeof(PlayerContext)},null);
        // MethodInfo method=thisType.GetMethod(methodName,BindingFlags.Static|BindingFlags.NonPublic);
        if(method==null){
            Debug.LogError(string.Format("没有找到方法{0:G},采用缺省Muzzle值",methodName));
        }else{
            object invokeRet=method.Invoke(null,new object[]{context});
            if(invokeRet is Muzzle || invokeRet==default){
                muzzle=invokeRet as Muzzle;
            }else{
                Debug.LogError(string.Format("方法{0:G}的返回类型,不是Muzzle",methodName));
            }
        }
        if(muzzle!=default){
            muzzles=MuzzlesWithBulletType(context,muzzle);
        }

        return muzzles!=default;
    }


    // *--------------无状态下射击--------------
    private static Muzzle NoneNormal(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle None3DBoss(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle None3D(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }


    // *--------------翻滚状态下射击--------------
    private static Muzzle RollNormal(PlayerContext context)
    {
        Muzzle ret = new();
        Vector2 dir = context.KeyDirection;
        Vector2 lookAt = context.LookAt;
        if (dir.x == 0 && dir.y == 0)
        {
                dir = lookAt;
        }
        Vector2 offset = context.RollBodyPosition();
        offset += (10f / 16f * dir.x) * Vector2.right;
        offset += (10f / 16f * dir.y) * Vector2.up;

        ret.firePosition = offset;
        ret.targetPosition = offset + dir;
        ret.targetLimit = false;
        return ret;
    }
    private static Muzzle Roll3DBoss(PlayerContext context)
    {
        /**
        * * "3D Boss"关卡不按左右键时向上攻击
        */
        Muzzle ret = new();
        Vector2 dir = context.KeyDirection;
        Vector2 lookAt = context.LookAt;
        if(dir.y<0){
            dir.y=0;
        }
        if (dir.x == 0 && dir.y == 0)
        {
            dir = Vector2.up;
        }
        
        Vector2 offset = context.RollBodyPosition();
        offset += (10f / 16f * dir.x) * Vector2.right;
        offset += (10f / 16f * dir.y) * Vector2.up;

        ret.firePosition = offset;
        ret.targetPosition = offset + dir;
        ret.targetLimit = false;
        return ret;
    }

    private static Muzzle Roll3D(PlayerContext context)
    {
        /**
        * * 3D关卡中只能向前攻击
        */
        Muzzle ret = new();
        Camera3DLevel c3DLevel=context.Get3DLevel();
        Vector2 pos = context.RollBodyPosition();

        pos += (10f / 16f) * Vector2.up;

        ret.firePosition=pos;
        ret.targetPosition=c3DLevel.TransformPlayerViewToEnemyView(pos);
        ret.targetLimit=true;
        return ret; 
    }


    // *--------------行走状态下射击--------------
    private static Muzzle LandNormal(PlayerContext context){
        Muzzle ret=new();
        Vector2 dir = context.KeyDirection;
        Vector2 lookAt = context.LookAt;
        if (dir.x == 0 && dir.y == 0)
        {
            dir = lookAt;
        }
        Vector2 offset = context.UpperBodyPosition();
        if (dir.x == 0f && dir.y == 1f)
        {
            //向上射击
            offset += (4f / 16f) * lookAt.x * Vector2.right ;
            offset += (24f / 16f) * Vector2.up;
        }
        else if (dir.x != 0f && dir.y != 0f)
        {
            if (dir.y > 0)
            {
                //斜上射击
                offset += (9f / 16f) * dir.x * Vector2.right ;
                offset += (14f / 16f) * Vector2.up;
            }
            else
            {
                //斜下射击
                offset += (9f / 16f) * dir.x * Vector2.right ;
                offset += (3f / 16f) * Vector2.down;
            }
        }
        else
        {
            //平射
            offset += (15f / 16f) * lookAt.x * Vector2.right ;
            offset += (4f / 16f) * Vector2.up;
        }
        ret.firePosition=offset;
        ret.targetPosition=offset+dir;
        ret.targetLimit=false;
        return ret;
    }
    private static Muzzle Land3DBoss(PlayerContext context){
        Muzzle ret=new();
        Vector2 dir = context.KeyDirection;
        Vector2 lookAt = context.LookAt;
        if(dir.y<0){
            dir.y=0;
        }
        if (dir.x == 0 && dir.y == 0)
        {
            dir = Vector2.right;
        }
        Vector2 offset = context.UpperBodyPosition();
        if (dir.x == 0f && dir.y == 1f)
        {
            //向上射击
            offset += (4f / 16f) * lookAt.x * Vector2.right ;
            offset += (24f / 16f) * Vector2.up;
        }
        else if (dir.x != 0f && dir.y != 0f)
        {
            //斜上射击
            offset += (9f / 16f) * dir.x * Vector2.right ;
            offset += (14f / 16f) * Vector2.up;
        }
        else
        {
            //平射
            offset += (15f / 16f) * lookAt.x * Vector2.right ;
            offset += (4f / 16f) * Vector2.up;
        }
        ret.firePosition=offset;
        ret.targetPosition=offset+dir;
        ret.targetLimit=false;
        return ret;
    }
    private static Muzzle Land3D(PlayerContext context){
        Muzzle ret=new();
        Camera3DLevel c3DLevel=context.Get3DLevel();
        Vector2 offset=context.UpperBodyPosition();
        offset += (24f / 16f) * Vector2.up;
        
        ret.firePosition= offset;
        ret.targetPosition= c3DLevel.TransformPlayerViewToEnemyView(ret.firePosition);
        ret.targetLimit=true;
        return ret;
    }
    
    // *--------------下落状态下射击--------------
    private static Muzzle FallNormal(PlayerContext context){
        return LandNormal(context);
    }
    private static Muzzle Fall3DBoss(PlayerContext context){
        // * "3D Boss"模式下不应出现Fall状态
        return default;
    }
    private static Muzzle Fall3D(PlayerContext context){
        // * 3D模式下不应出现Fall状态
        return default;
    }

    // *--------------趴下状态下射击--------------
    private static Muzzle ProstrateNormal(PlayerContext context){
        Muzzle ret=new();
        Vector2 lookAt=context.LookAt;
        Vector2 offset = context.ProstrateBodyPosition();
        offset += (lookAt.x * 20f / 16f) * Vector2.right + (9f / 16f) * Vector2.up;
        
        ret.firePosition=offset;
        ret.targetPosition=offset+lookAt.x*Vector2.right;
        ret.targetLimit=false;

        return ret;
    }
    private static Muzzle Prostrate3DBoss(PlayerContext context){
        // * "3D Boss"模式下不应出现趴下状态
        return default;
    }
    private static Muzzle Prostrate3D(PlayerContext context){
        Muzzle ret=new();
        Camera3DLevel c3DLevel=context.Get3DLevel();
        Vector2 offset=context.ForwardProstrateBodyPosition();
        offset += (28f/16f)*Vector2.up;

        ret.firePosition=offset;
        ret.targetPosition=c3DLevel.TransformPlayerProstrateViewToEnemyView(ret.firePosition);
        ret.targetLimit=true;

        return ret;
    }


    // *--------------落水水花状态下射击--------------
    private static Muzzle SplashNormal(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle Splash3DBoss(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle Splash3D(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }

    // *--------------落水状态下射击--------------
    private static Muzzle FallInWaterNormal(PlayerContext context){
        Muzzle ret=new();
        Vector2 dir = context.KeyDirection;
        Vector2 lookAt = context.LookAt;
        if (dir.x == 0 && dir.y == 0)
        {
            dir = lookAt;
        }
        if(dir.y<0){
            dir.y=0;
        }
        Vector2 offset = context.InWaterBodyPosition();
        if (dir.x == 0f && dir.y == 1f)
        {
            //向上射击
            offset += (4f / 16f) * lookAt.x * Vector2.right ;
            offset += (24f / 16f) * Vector2.up;
        }
        else if (dir.x != 0f && dir.y != 0f)
        {
            //斜上射击
            offset += (9f / 16f) * dir.x * Vector2.right ;
            offset += (14f / 16f) * Vector2.up;
        }
        else
        {
            //平射
            offset += (15f / 16f) * lookAt.x * Vector2.right ;
            offset += (4f / 16f) * Vector2.up;
        }
        ret.firePosition=offset;
        ret.targetPosition=offset+dir;
        ret.targetLimit=false;
        return ret;
    }
    private static Muzzle FallInWater3DBoss(PlayerContext context){
        // * "3D Boss"模式下不应出现此状态
        return default;
    }
    private static Muzzle FallInWater3D(PlayerContext context){
        // * "3D Boss"模式下不应出现此状态
        return default;
    }

    // *--------------潜水状态下射击--------------
    private static Muzzle HideInWaterNormal(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle HideInWater3DBoss(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle HideInWater3D(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }

    // *--------------上岸状态下射击--------------
    private static Muzzle GoingAshoreNormal(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle GoingAshore3DBoss(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle GoingAshore3D(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }

    // *--------------死亡状态下射击--------------
    private static Muzzle DieNormal(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle Die3DBoss(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }
    private static Muzzle Die3D(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }

    // *--------------3D向前状态下射击--------------
    private static Muzzle IdleNormal(PlayerContext context){
        // * 普通模式下不应出现此状态
        return default;
    }
    private static Muzzle Idle3DBoss(PlayerContext context){
        Muzzle ret=new();
        Vector2 offset=context.ForwardBodyPosition();
        offset += (41f / 16f) * Vector2.up;

        ret.firePosition=offset;
        ret.targetPosition=offset+Vector2.up;
        ret.targetLimit=false;
                
        return ret;
    }
    private static Muzzle Idle3D(PlayerContext context){
        Muzzle ret=new();
        Camera3DLevel c3DLevel=context.Get3DLevel();
        Vector2 offset=context.ForwardBodyPosition();
        offset += (41f / 16f) * Vector2.up;

        ret.firePosition=offset;
        ret.targetPosition=c3DLevel.TransformPlayerViewToEnemyView(ret.firePosition);
        ret.targetLimit=true;

        return ret;
    }

    // *--------------3D被电击状态下射击--------------
    private static Muzzle ElectricShockNormal(PlayerContext context){
        // * 普通模式下不应出现此状态
        return default;
    }
    private static Muzzle ElectricShock3DBoss(PlayerContext context){
        // * "3D Boss"模式下不应出现此状态
        return default;
    }
    private static Muzzle ElectricShock3D(PlayerContext context){
        // * 此状态下不应射击
        return default;
    }

    // *--------------3D向前跑状态下射击--------------
    private static Muzzle GoAheadNormal(PlayerContext context){
        // * 普通模式下不应出现此状态
        return default;
    }
    private static Muzzle GoAhead3DBoss(PlayerContext context){
        // * "3D Boss"模式下不应出现此状态
        return default;
    }
    private static Muzzle GoAhead3D(PlayerContext context){
        Muzzle ret=new();
        Camera3DLevel c3DLevel=context.Get3DLevel();
        Vector2 lookAt=context.LookAt;
        Vector2 offset=context.GoAheadBodyPosition();
        offset += (39f / 16f) * Vector2.up;
        offset += lookAt.x*(6.5f / 16f) * Vector2.right;

        ret.firePosition=offset;
        ret.targetPosition=c3DLevel.TransformPlayerViewToEnemyView(ret.firePosition);
        ret.targetLimit=true;

        return ret;
    }

    private static Muzzle[] MuzzlesWithBulletType(PlayerContext context,Muzzle muzzle){
        Muzzle[] ret=default;
        if(!context.Is3DLevel()|| context.Is3DBossLevel()){
            ret=MuzzlesWithBulletTypeNormal(context,muzzle);
        }else if(context.Is3DLevel() && !context.Is3DBossLevel()){
            ret=MuzzlesWithBulletType3D(context,muzzle);
        }
        return ret;

    }

    private static Muzzle[] MuzzlesWithBulletTypeNormal(PlayerContext context,Muzzle muzzle){
        Muzzle[] ret=default;
        if(muzzle!=default){
            ABullet.BulletType bulletType=context.GetBulletType();
            //正常模式
            switch (bulletType)
            {
                case ABullet.BulletType.S:
                {
                    float gapArg = 12f;
                    int bulletCount = 5;//(int)(360/gapArg)
                    ret = new Muzzle[bulletCount];
                    float roatArg = (ret.Length - 1) / 2f * gapArg;
                    for (int i = 0; i < ret.Length; i++)
                    {
                        float arg = gapArg * i - roatArg+muzzle.Angle;
                        Quaternion angle=Quaternion.AngleAxis(arg,Vector3.forward);
                        Vector2 offset=angle*Vector2.right;
                        // float argRad = arg * Mathf.Deg2Rad;
                        // float x = muzzle.Direction.x * Mathf.Cos(argRad) + muzzle.Direction.y * Mathf.Sin(argRad);
                        // float y = -muzzle.Direction.x * Mathf.Sin(argRad) + muzzle.Direction.y * Mathf.Cos(argRad);
                        ret[i] = new Muzzle()
                        {
                            firePosition = muzzle.firePosition,
                            targetPosition= muzzle.firePosition+offset,
                            targetLimit=muzzle.targetLimit,
                        };

                    }
                }
                break;
                case ABullet.BulletType.L:
                {
                    Vector3 cross = Vector3.Cross(Vector2.right, muzzle.Direction);
                    float angle = Vector2.Angle(Vector2.right, muzzle.Direction);
                    angle *= cross.z;
                    int count = 4;
                    int offset = -4;
                    Ray2D ray = new(muzzle.firePosition, muzzle.Direction);
                    ret = new Muzzle[count];
                    for (int i = offset; i < offset + count; i++)
                    {
                        int index = i - offset;
                        Vector2 pos = ray.GetPoint(i);
                        ret[index] = new Muzzle()
                        {
                            firePosition = pos,
                            targetPosition = pos+muzzle.Direction,
                        };
                    }
                }
                    break;
                default:
                    ret = new Muzzle[]{muzzle};
                    break;

            }
        }
        return ret;
    }
    private static Muzzle[] MuzzlesWithBulletType3D(PlayerContext context,Muzzle muzzle){
        Muzzle[] ret=default;
        if(muzzle!=default){
            ABullet.BulletType bulletType=context.GetBulletType();
            //伪3D模式
            switch (bulletType)
            {
                case ABullet.BulletType.S:
                    {
                        float gapArg = 6f;
                        int bulletCount = 5;//(int)(360/gapArg)
                        ret = new Muzzle[bulletCount];
                        float roatArg = (ret.Length - 1) / 2f * gapArg;

                        Vector2 axisZ = muzzle.targetPosition - muzzle.firePosition;
                        float angle = Vector2.SignedAngle(Vector2.right, axisZ);
                        float distance = Vector2.Distance(muzzle.targetPosition, muzzle.firePosition);

                        for (int i = 0; i < ret.Length; i++)
                        {
                            float arg = gapArg * i - roatArg;

                            float argRad = (angle + arg) * Mathf.Deg2Rad;
                            float x = Mathf.Cos(argRad) * distance;
                            Vector2 targetPosition = new Vector2(x, axisZ.y) + muzzle.firePosition;
                            Vector2 direction = muzzle.targetPosition - muzzle.firePosition;
                            direction.Normalize();
                            ret[i] = new Muzzle()
                            {
                                firePosition = muzzle.firePosition,
                                targetPosition=targetPosition,
                                targetLimit=muzzle.targetLimit,
                            };
                        }
                    }
                    break;
                case ABullet.BulletType.L:
                    {
                        Vector3 cross = Vector3.Cross(Vector2.right, muzzle.Direction);
                        Vector2 direction=muzzle.Direction.normalized;
                        float angle = Vector2.Angle(Vector2.right, direction);
                        int count = 4;
                        int offset = -4;
                        Ray2D ray = new(muzzle.firePosition, direction);
                        ret = new Muzzle[count];
                        for (int i = offset; i < offset + count; i++)
                        {
                            int index = i - offset;
                            Vector2 pos = ray.GetPoint(i);
                            ret[index] = new Muzzle()
                            {
                                firePosition = pos,
                                targetPosition = muzzle.targetPosition,
                                targetLimit=true,
                            };
                        }
                    }
                    break;
                default:
                    {
                        ret = new Muzzle[]{muzzle};
                    }
                    break;

            }
        }
        return ret;
    }

}
